% =========================================================================
% This code was modifed from code for Super-Resolution Convolutional Neural Networks (SRCNN)
%
% Reference
%   Chao Dong, Chen Change Loy, Kaiming He, Xiaoou Tang. Learning a Deep Convolutional Network for Image Super-Resolution, 
%   in Proceedings of European Conference on Computer Vision (ECCV), 2014
% =========================================================================

function [result] = Matting_forward(model, input)
input=gpuArray(input);
%% load CNN model parameters
load(model);
%% setting
weights_conv1=gpuArray(weights_conv1);
weights_conv2_1=gpuArray(weights_conv2_1);
weights_conv2_2=gpuArray(weights_conv2_2);
weights_conv2_3=gpuArray(weights_conv2_3);
weights_conv2_4=gpuArray(weights_conv2_4);
weights_conv3=gpuArray(weights_conv3);
biases_conv2_1=gpuArray(biases_conv2_1);
biases_conv2_2=gpuArray(biases_conv2_2);
biases_conv2_3=gpuArray(biases_conv2_3);
biases_conv2_4=gpuArray(biases_conv2_4);
biases_conv3=gpuArray(biases_conv3);
biases_conv1=gpuArray(biases_conv1);
[conv1_channel,conv1_patchsize2,conv1_filters] = size(weights_conv1);
conv1_patchsize = sqrt(conv1_patchsize2);
[conv2_1_channels,conv2_1_patchsize2,conv2_1_filters] = size(weights_conv2_1);
conv2_1_patchsize = sqrt(conv2_1_patchsize2);
[conv2_2_channels,conv2_2_patchsize2,conv2_2_filters] = size(weights_conv2_2);
conv2_2_patchsize = sqrt(conv2_2_patchsize2);
[conv2_3_channels,conv2_3_patchsize2,conv2_3_filters] = size(weights_conv2_3);
conv2_3_patchsize = sqrt(conv2_3_patchsize2);
[conv2_4_channels,conv2_4_patchsize2,conv2_4_filters] = size(weights_conv2_4);
conv2_4_patchsize = sqrt(conv2_4_patchsize2);

[conv3_channels,conv3_patchsize2] = size(weights_conv3);
conv3_patchsize = sqrt(conv3_patchsize2);

[hei, wid, ch] = size(input);

%% conv1
weights_conv1 = reshape(weights_conv1, conv1_channel, conv1_patchsize, conv1_patchsize, conv1_filters);
conv1_data = gpuArray.zeros(hei, wid, conv1_filters);
for i = 1 : conv1_filters
    for j = 1 :conv1_channel
        conv1_subfilter = reshape(weights_conv1(j,:,:,i), conv1_patchsize, conv1_patchsize);
        conv1_data(:,:,i) = conv1_data(:,:,i) + imfilter(input(:,:,j), conv1_subfilter, 'same', 'replicate');
        
    end 
    conv1_data(:,:,i) = max(conv1_data(:,:,i) + biases_conv1(i), 0);
end

%% conv2
conv2_1_data = gpuArray.zeros(hei, wid, conv2_1_filters);
for i = 1 : conv2_1_filters
    conv2_1_data(:,:,i) = sum(conv1_data(:,:,:).* repmat(reshape(weights_conv2_1(:,:,i),[1 1 conv1_filters]),[hei, wid, 1]),3);
    conv2_1_data(:,:,i) = max(conv2_1_data(:,:,i) + biases_conv2_1(i), 0);
end
%% conv2
conv2_2_data = gpuArray.zeros(hei, wid, conv2_2_filters);
for i = 1 : conv2_2_filters
    conv2_2_data(:,:,i) = sum(conv2_1_data(:,:,:).* repmat(reshape(weights_conv2_2(:,:,i),[1 1 conv2_1_filters]),[hei, wid, 1]),3);
    conv2_2_data(:,:,i) = max(conv2_2_data(:,:,i) + biases_conv2_2(i), 0);
end
%% conv2
conv2_3_data = gpuArray.zeros(hei, wid, conv2_3_filters);
for i = 1 : conv2_3_filters
    conv2_3_data(:,:,i) = sum(conv2_2_data(:,:,:).* repmat(reshape(weights_conv2_3(:,:,i),[1 1 conv2_2_filters]),[hei, wid, 1]),3);
    conv2_3_data(:,:,i) = max(conv2_3_data(:,:,i) + biases_conv2_3(i), 0);
end
%% conv2
conv2_4_data = gpuArray.zeros(hei, wid, conv2_4_filters);
for i = 1 : conv2_4_filters 
    conv2_4_data(:,:,i) = sum(conv2_3_data(:,:,:).* repmat(reshape(weights_conv2_4(:,:,i),[1 1 conv2_3_filters]),[hei, wid, 1]),3);
    conv2_4_data(:,:,i) = max(conv2_4_data(:,:,i) + biases_conv2_4(i), 0);
end


%% conv3
conv3_data = gpuArray.zeros(hei, wid);
for i = 1 : conv3_channels
    conv3_subfilter = reshape(weights_conv3(i,:), conv3_patchsize, conv3_patchsize);
    conv3_data(:,:) = conv3_data(:,:) + imfilter(conv2_4_data(:,:,i), conv3_subfilter, 'same', 'replicate');
end

%%  reconstruction
result = conv3_data(:,:) + biases_conv3;
result=gather(result);




